package drds.server.net;

import java.io.IOException;
import java.util.Iterator;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import drds.server.Server;
import drds.server.buffer.ByteBufferPool;
import drds.server.datasource.IConnectionHolder;
import drds.server.util.CurrentTimeMillis;
import drds.server.util.Executor;

/**
 * SessionContext组共享资源管理
 * 
 * @author 曹正辉<330937205@qq.com>
 * 
 */
public final class SessionContextGroupShareResources {
	private static final Logger LOGGER = LoggerFactory.getLogger(SessionContextGroupShareResources.class);
	private final String name;
	private final ByteBufferPool byteBufferPool;
	private final Executor executor;
	// 前端连接
	private final ConcurrentMap<Long, ISessionContext> sessionContextMap;
	// 后端连接
	private final ConcurrentMap<Long, IConnectionHolder> connectionHolderMap;
	//
	private long netInByteSize;
	private long netOutByteSize;

	public SessionContextGroupShareResources(String name, ByteBufferPool byteBufferPool, Executor executor) throws IOException {
		this.name = name;
		this.byteBufferPool = byteBufferPool;
		this.executor = executor;
		this.sessionContextMap = new ConcurrentHashMap<Long, ISessionContext>();
		this.connectionHolderMap = new ConcurrentHashMap<Long, IConnectionHolder>(1024);
	}

	public String getName() {
		return name;
	}

	public ByteBufferPool getByteBufferPool() {
		return byteBufferPool;
	}

	public Executor getExecutor() {
		return this.executor;
	}

	public long getNetInBytes() {
		return this.netInByteSize;
	}

	public void addNetInBytes(long bytes) {
		this.netInByteSize += bytes;
	}

	public long getNetOutBytes() {
		return this.netOutByteSize;
	}

	public void addNetOutBytes(long bytes) {
		this.netOutByteSize += bytes;
	}

	public void addSessionContext(ISessionContext sessionContext) {
		this.sessionContextMap.put(sessionContext.getId(), sessionContext);
	}

	public ConcurrentMap<Long, ISessionContext> getSessionContextMap() {
		return this.sessionContextMap;
	}

	public void put(IConnectionHolder connectionHolder) {
		this.connectionHolderMap.put(connectionHolder.getId(), connectionHolder);
	}

	public ConcurrentMap<Long, IConnectionHolder> getConnectionHolderMap() {
		return this.connectionHolderMap;
	}

	public void checkSessionContext() {
		Iterator<Entry<Long, ISessionContext>> iterator = sessionContextMap.entrySet().iterator();
		while (iterator.hasNext()) {
			ISessionContext sessionContext = iterator.next().getValue();
			// 删除空连接
			if (sessionContext == null) {
				iterator.remove();
				continue;
			}

			// 清理已关闭连接，否则空闲检查。
			if (sessionContext.isClosed()) {
				((SessionContext$ReadWrite) sessionContext).cleanup();
				iterator.remove();
			} else {
				// very important ,for some data maybe not sent
				checkriteByteBufferQueue((SessionContext$ReadWrite) sessionContext);
				sessionContext.idleCheck();
			}
		}
	}

	/**
	 * 数据写出
	 */
	private void checkriteByteBufferQueue(SessionContext$ReadWrite sessionContext) {
		// very important ,for some data maybe not sent
		if (!sessionContext.writeByteBufferQueue.isEmpty()) {
			sessionContext.getReadWrite().write();
		}
	}

	// 数据库连接 需要注册到session上下文，这样的好处是防止内存泄漏。
	public void checkJdbcConnectionHolder() {
		long sqlTimeout = Server.getInstance().getConfig().getDRDS().getSqlExecuteTimeout() * 1000L;
		Iterator<Entry<Long, IConnectionHolder>> iterator = connectionHolderMap.entrySet().iterator();
		while (iterator.hasNext()) {
			IConnectionHolder connectionHolder = iterator.next().getValue();

			// 删除空连接
			if (connectionHolder == null) {
				iterator.remove();
				continue;
			}
			// SQL执行超时的连接关闭
			if (connectionHolder.isBorrowed() && //
					connectionHolder.getLastTime() < CurrentTimeMillis.currentTimeMillis() - sqlTimeout) {
				LOGGER.error("found backend connection SQL timeout ,close it " + connectionHolder);
				connectionHolder.close("sql timeout");
				iterator.remove();
				continue;
			}

			// 清理已关闭连接，否则空闲检查。
			connectionHolder.idleCheck();
		}
	}

	public void removeSessionContext(ISessionContext sessionContext) {
		this.sessionContextMap.remove(sessionContext.getId());

	}

	// jdbc连接用这个释放
	public void removeConnectionHolder(IConnectionHolder connectionHolder) {
		this.connectionHolderMap.remove(connectionHolder.getId());
	}

}